package com.jms.boot.config.builder;

import com.jms.boot.config.JmsBootConfig;
import com.jms.framework.config.JmsAbstractConfig;
import com.jms.framework.config.JmsConfig;
import com.jms.framework.config.JmsConfigItem;

import java.util.*;

/**
 * 配置构建器类，用于动态构建和管理应用程序的配置
 */
public class ConfigBuilder {

    // 单例模式的实例变量
    private volatile static ConfigBuilder instance;

    // 存储加载的配置信息
    private JmsBootConfig jmsConfig;

    // 存储配置类的Class对象
    private Class<?> bootClass;

    // 存储命令行参数
    private String[] args;

    // 私有构造方法，防止外部实例化
    private ConfigBuilder(){
    }

    /**
     * 获取ConfigBuilder的单例实例
     * @return ConfigBuilder的实例
     */
    public static ConfigBuilder getInstance(){
        if (instance == null) {
            synchronized (ConfigBuilder.class) {
                if (instance == null) {
                    instance = new ConfigBuilder();
                }
            }
        }
        return instance;
    }

    /**
     * 构建配置的入口方法
     * @param bootClass 配置类的Class对象
     * @param args 命令行参数
     * @return ConfigBuilder实例，用于链式调用
     */
    public ConfigBuilder builder(Class<?> bootClass, String[] args) {
        this.bootClass = bootClass;
        this.args = args;
        loadConfig();
        return this;
    }

    /**
     * 加载配置信息，包括配置文件的名称、类型和位置
     */
    private void loadConfig(){
        // 默认的配置文件名和类型
        String configName = JmsConfigItem.JMS_CONFIG_FILE_DEFAULT_NAME.getValue();
        String configType = JmsAbstractConfig.PROPERTIES_TYPE;

        // 如果配置类上有ApplicationBoot注解，则根据注解的值来设置配置文件的名称和类型
        if (bootClass.isAnnotationPresent(com.jms.boot.annotation.ApplicationBoot.class)) {
            com.jms.boot.annotation.ApplicationBoot boot = bootClass.getAnnotation(com.jms.boot.annotation.ApplicationBoot.class);
            if (boot.configName() != null && !boot.configName().equals("")) {
                configName = boot.configName();
            }
            if (boot.configType() != null && !boot.configType().equals("")) {
                configType = boot.configType();
            }
        }

        // 从命令行参数中解析配置文件的位置和类型
        String configLocation = null;
        for (String arg : args) {
            if (arg.startsWith("--jms.config.location=")) {
                configLocation = arg.substring(arg.indexOf("=") + 1);
                configType = configLocation.substring(configLocation.lastIndexOf(".") + 1);
                configName = configLocation.substring(0, configLocation.lastIndexOf("."));
            }
        }

        // 使用JmsBootConfig的实例来设置和管理配置信息
        this.jmsConfig = JmsBootConfig.getInstance().setBootClass(bootClass).setConfigName(configName).setConfigLocation(configLocation).setConfigType(configType);
        jmsConfig.resolveConfig();
    }

    /**
     * 构建并返回JmsConfig实例
     * @return JmsConfig实例
     */
    public JmsConfig build() {
        destroy();
        return jmsConfig;
    }

    /**
     * 销毁单例实例，以便于垃圾回收
     */
    public void destroy(){
        instance = null;
    }

    /**
     * 将属性文件中的属性复制到配置对象的属性中
     * @return ConfigBuilder实例，用于链式调用
     */
    public ConfigBuilder copyPropertiesToAttributes(){
        Properties properties = jmsConfig.getProperties();
        for (Map.Entry<Object, Object> entry : properties.entrySet()) {
            jmsConfig.setAttribute(entry.getKey().toString(), entry.getValue().toString());
        }
        return this;
    }

    /**
     * 获取组件扫描基础路径，包括：
     *  1.配置文件中的属性
     *  2.启动类所在包
     * @return ConfigBuilder实例，用于链式调用
     */
    public ConfigBuilder getBaseComponentScanPaths(){
        Properties properties = jmsConfig.getProperties();
        List<String> componentScanPaths = new ArrayList<>();
        // 从配置属性中获取组件扫描路径
        String propertyScans = properties.getProperty(JmsConfigItem.COMPONENT_SCAN_BASE_PATHS.getValue());
        if (propertyScans != null) {
            for (String propertyScan : propertyScans.split(",")) {
                componentScanPaths.add(propertyScan.trim());
            }
        }
        // 将启动类所在的包作为扫描路径
        componentScanPaths.add(jmsConfig.getBootClass().getPackage().getName());
        // 将扫描路径保存到配置对象中
        jmsConfig.setAttribute(JmsConfigItem.COMPONENT_SCAN_BASE_PATHS.getValue(), String.join(",", componentScanPaths));
        return this;
    }

}
